/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Game;

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.LayerManager;
import javax.microedition.lcdui.game.Sprite;
import javax.microedition.lcdui.game.TiledLayer;

/**
 *
 * @author Vinicio Gomez
 */
public class GameDriver extends GameCanvas implements Runnable{
    
    private static final int MIN_BUFFER = 80;
    private int x=0;
    private int indice=0;
    private int viewPortX = 0;
    private int viewPortY = 0;
    /**La direccion del ultimo movimiento*/
    private byte lastDirection = -1;
    /**Cantidad de pixeles que se mueve el jugador*/
    private static final int SPEED = 3;
    /**Indica si el juego debe finalizar*/
    private boolean interrupted;
    /**El administrador de las layers*/
    private LayerManager lm;
    /**Jugador*/
    private Sprite spriteJugador;
    /**Layer de obstaculos del mapa*/
    private TiledLayer tlArena;
    private TiledLayer tlPalmeras;
    private TiledLayer tlTesoro;
    /**Diseño del juego*/
    private Game gameDesign;
    private boolean tresure=false;
    private int[] instrucciones;
    public boolean cargarMapa=false;
    public Menu aplicacion;
    
    /**
     *  animate the duke sprite
     */
    private SpriteAnimationTask spriteJugadorAnimator;
    private Timer timer;
    /*
     * 
     */
    public boolean automatico=false;
    private final int[][] elmapa;
    
    public GameDriver (Menu aplicacion, int[][]elmapa){
        
        super(true);
        this.elmapa=elmapa;
        this.aplicacion=aplicacion;
        automatico=false;
        try {
            this.setFullScreenMode(true);
            this.init();
        } catch (IOException ex) {
            
        }
    }
    public GameDriver (Menu aplicacion, int[][] elmapa ,int[] instrucciones, Object objeto){
        super(true);
        this.elmapa=elmapa;
        this.aplicacion=aplicacion;
        this.instrucciones=instrucciones;
        try {
            automatico=true;
            this.setFullScreenMode(true);
            this.init();
        } catch (IOException ex) {
            
        }
    }
    
    public GameDriver (Menu aplicacion, int[][] elmapa ,int[] instrucciones){
        super(true);
        this.elmapa=elmapa;
        this.aplicacion=aplicacion;
        this.instrucciones=instrucciones;
        try {
            automatico=true;
            this.setFullScreenMode(true);
            this.init();
        } catch (IOException ex) {
            
        }
    }
    
    /**
     * Inicializacion del Diseño del Juego, carga las layers y las animaciones.
     */
    private void init() throws IOException {
        this.timer = new Timer();
        
        this.gameDesign = new Game(elmapa);

        this.spriteJugador = gameDesign.getPiratas_f();
 
        this.spriteJugador.defineReferencePixel(spriteJugador.getHeight()/2, spriteJugador.getWidth()/2);
        //animacion
        this.spriteJugadorAnimator = new SpriteAnimationTask(this.spriteJugador, false);
        this.timer.scheduleAtFixedRate(this.spriteJugadorAnimator, 0, gameDesign.piratas_fseq001Delay);

        
        this.tlArena = this.gameDesign.getArena();
        this.tlPalmeras = this.gameDesign.getPalmera();
        this.tlTesoro = this.gameDesign.getTesoro_f();
        this.lm = new LayerManager();
        gameDesign.updateLayerManagerForMapa1(lm);
    }
    
    
    
    public void run() {
        //throw new UnsupportedOperationException("Not supported yet.");
        Graphics g = getGraphics();
        while (!this.interrupted) {
            if (tresure){
                try {
                    Thread.sleep(1500);
                } catch (InterruptedException ex) {
                   
                }
                timer.cancel();
                tresure=false;
                this.stop();
                
                aplicacion.switchDisplayable(null,aplicacion.getWin());
                
            }
            //ingreso del usuario
            
            int keyState=getKeyStates();
            if (automatico){
                    x++;        
                if (x>20){
                    //siguiente elemento del vector
                    indice++;
                    x=0;
                    if (indice==instrucciones.length||instrucciones[indice]==-1 || instrucciones.length == 0){
                        keyState = getKeyStates();
                        automatico=false;
                    }
                }else{
                        keyState = instrucciones[indice];
                    }
            }else{
                keyState = getKeyStates();
            }
            
            
            //se presiono a la izquierda
            if ((keyState & LEFT_PRESSED) != 0) { 
                if (this.lastDirection != LEFT) {
                    this.lastDirection = LEFT;
                    //agregar animacion
                        this.spriteJugador.setFrameSequence(gameDesign.piratas_fseq001);
                        this.spriteJugador.setTransform(Sprite.TRANS_MIRROR);
                    continue;
                }
            //reproducir animacion al reves 
            this.spriteJugadorAnimator.forward();
            this.spriteJugador.move(-SPEED, 0);
            //verificar colision
            if (this.spriteCollides(this.spriteJugador)) {
                this.spriteJugador.move(SPEED, 0);
                continue;
            }
            //el jugador no se puede salir del mapa
            //el mapa se mueve para que el jugador no se salga
            this.adjustViewport(this.viewPortX - SPEED, this.viewPortY);
            }            
            //se presiono a la derecha
            else if ((keyState & RIGHT_PRESSED) != 0) {
                if (this.lastDirection != RIGHT) {
                    this.lastDirection = RIGHT;
                    //agregar animacion 
                    this.spriteJugador.setFrameSequence(gameDesign.piratas_fseq001);
                    this.spriteJugador.setTransform(Sprite.TRANS_NONE);
                    continue;
                }
                this.spriteJugadorAnimator.forward();
                this.spriteJugador.move(SPEED, 0);
                //verificar colision
                if (this.spriteCollides(this.spriteJugador)) {
                    this.spriteJugador.move(-SPEED, 0);
                    continue;
                }
                //el jugador no se puede salir del mapa
                //el mapa se mueve para que el jugador no se salga
            this.adjustViewport(this.viewPortX + SPEED, this.viewPortY);  
            }
            //se presiono hacia arriba
            else if ((keyState & UP_PRESSED) != 0) {
                if (this.lastDirection != UP) {
                    this.lastDirection = UP;
                    //agregar animacion 
                    this.spriteJugador.setFrameSequence(gameDesign.piratas_fseq001);
                    this.spriteJugador.setTransform(Sprite.TRANS_MIRROR_ROT90);
                    continue;
                }
                this.spriteJugadorAnimator.forward();
                this.spriteJugador.move(0,-SPEED);
                //verificar colision
                if (this.spriteCollides(this.spriteJugador)) {
                    this.spriteJugador.move(0, SPEED);
                    continue;
                }
                //el jugador no se puede salir del mapa
                //el mapa se mueve para que el jugador no se salga
            this.adjustViewport(this.viewPortX, this.viewPortY - SPEED);  
            }
            //se presiono hacia abajo
            else if ((keyState & DOWN_PRESSED) != 0) {
                if (this.lastDirection != DOWN) {
                    this.lastDirection = DOWN;
                    //agregar animacion 
                    this.spriteJugador.setFrameSequence(gameDesign.piratas_fseq001);
                    this.spriteJugador.setTransform(Sprite.TRANS_MIRROR_ROT270);
                    continue;
                }
                this.spriteJugadorAnimator.forward();
                this.spriteJugador.move(0, SPEED);
                //verificar colision
                if (this.spriteCollides(this.spriteJugador)) {
                    this.spriteJugador.move(0, -SPEED);
                    continue;
                }
                //el jugador no se puede salir del mapa
                //el mapa se mueve para que el jugador no se salga
            this.adjustViewport(this.viewPortX, this.viewPortY + SPEED);
            }
            //no se presiono nada
            else {
                this.spriteJugadorAnimator.setMoving(false);
            }
            //se pintan los cambios
            this.lm.paint(g, 0, 0);
            //se verifica que se realicen mientras el sistema no esta ocupado
            flushGraphics(0, 0, this.getWidth(), this.getHeight());
            //se espera cierto tiempo antes de la proxima instruccion
            try {
                Thread.sleep(20);
            } catch (InterruptedException ex) {
                
            }
        }
        //prueba de finalizar juego.
        
    }
    
    public void stop (){
        this.interrupted = true;
    }

    private boolean spriteCollides(Sprite sprite) {
        tresure = sprite.collidesWith(this.tlTesoro, true);
        
        return sprite.collidesWith(this.tlPalmeras, false) //
            || sprite.collidesWith(this.tlTesoro, true)  //  
            || sprite.getX() < 0 || sprite.getY() < 0   //salio del mapa 
            || sprite.getX() > (this.tlArena.getWidth() - sprite.getWidth()) 
            || sprite.getY() > (this.tlArena.getHeight() - sprite.getHeight()
            );
    
    }
    
    /**
     * TOMADO DE:
     * Creating Mobile Games: Using Java ME Platform to Put the Fun into Your Mobile Device and Cell Phone
     * Adjust the viewport to keep the main animated sprite inside the screen.
     * The coordinates are checked for game bounaries and adjusted only if it
     * makes sense.
     * Modificado: Vinicio Gomez
     * @param x viewport X coordinate
     * @param y viewport Y coordinate
     */
    private void adjustViewport(int x, int y) {

        int sx = this.spriteJugador.getX();
        int sy = this.spriteJugador.getY();

        int xmin = this.viewPortX + MIN_BUFFER;
        int xmax = this.viewPortX + this.getWidth() - this.spriteJugador.getWidth() - MIN_BUFFER;
        int ymin = this.viewPortY + MIN_BUFFER;
        int ymax = this.viewPortY + this.getHeight() - this.spriteJugador.getHeight() - MIN_BUFFER;

        //if the sprite is not near the any screen edges don't adjust
        if (sx >= xmin && sx <= xmax && sy >= ymin && sy <= ymax) {
            return;
        }

        //if the sprite is moving left but isn't near the left edge of the screen don't adjust
        if (this.lastDirection == LEFT && sx >= xmin) {
            return;
        }
        //if the sprite is moving right but isn't near the right edge of the screen don't adjust
        if (this.lastDirection == RIGHT && sx <= xmax) {
            return;
        }
        //if the sprite is moving up but isn't at near top edge of the screen don't adjust
        if (this.lastDirection == UP && sy >= ymin) {
            return;
        }
        //if the sprite is moving down but isn't at near bottom edge of the screen don't adjust
        if (this.lastDirection == DOWN && sy <= ymax) {
            return;
        }

        //only adjust x to values that ensure the base tiled layer remains visible
        //and no white space is shown
        if (x < this.tlArena.getX()) {
            this.viewPortX = this.tlArena.getX();
        } else if (x > this.tlArena.getX() + this.tlArena.getWidth() - this.getWidth()) {
            this.viewPortX = this.tlArena.getX() + this.tlArena.getWidth() - this.getWidth();
        } else {
            this.viewPortX = x;
        }

        //only adjust y to values that ensure the base tiled layer remains visible
        //and no white space is shown
        if (y < this.tlArena.getY()) {
            this.viewPortY = this.tlArena.getY();
        } else if (y > this.tlArena.getY() + this.tlArena.getHeight() - this.getHeight()) {
            this.viewPortY = this.tlArena.getY() + this.tlArena.getHeight() - this.getHeight();
        } else {
            this.viewPortY = y;
        }

        //adjust the viewport
        this.lm.setViewWindow(this.viewPortX, this.viewPortY, this.getWidth(), this.getHeight());
    }
    
    
    /**
     * Animates a sprite.
     */
    private class SpriteAnimationTask extends TimerTask {

        private boolean moving = false;
        private boolean forward = true;
        private Sprite sprite;

        public SpriteAnimationTask(Sprite sprite, boolean forward) {
            this.sprite = sprite;
            this.forward = forward;
        }

        public void run() {
            if (!this.moving) {
                return;
            }
            if (this.forward) {
                this.sprite.nextFrame();
            } else {
                this.sprite.prevFrame();
            }
        }

        public void forward() {
            this.forward = true;
            this.moving = true;
        }

        public void backward() {
            this.forward = false;
            this.moving = true;
        }

        public void setMoving(boolean isMoving) {
            this.moving = isMoving;
        }
    }
}